﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using Ensynch.ILM2.Workflow.Activities;
using Microsoft.IdentityManagement;
using Microsoft.IdentityManagement.WebUI;
using Microsoft.IdentityManagement.WebUI.Controls;
using Microsoft.IdentityManagement.WebUI.Controls.Resources;
using Microsoft.ResourceManagement.Utilities;
using Microsoft.ResourceManagement.WebServices.Client;
using Microsoft.ResourceManagement.WebServices.WSEnumeration;
using Microsoft.ResourceManagement.WebServices.WSResourceManagement;
using Microsoft.ResourceManagement.Workflow.Activities;

namespace Ensynch.ILM2.WebUI.Controls
{
    class UpdateAttributeActivitySettingsPart : ActivitySettingsPart
    {
        private Table mainTable = new Table();

        #region Override methods

        protected override void OnLoad(EventArgs e)
        {
            mainTable.Style.Add("background-image",
                Page.ClientScript.GetWebResourceUrl(this.GetType(),
                "Ensynch.ILM2.images.EnsynchWatermark.png"));
            mainTable.Style.Add("background-repeat", "no-repeat");
            mainTable.Style.Add("background-position", "center");
            mainTable.Style.Add("background-size", "100%");
            mainTable.BackColor = Color.White;

            base.OnLoad(e);
        }

        protected override void CreateChildControls()
        {
            this.InitializeControls();
            base.CreateChildControls();
        }

        public override Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow)
        {
            try
            {
                if (!this.ValidateInputs())
                {
                    return null;
                }
                UpdateAttributeActivity activity = new UpdateAttributeActivity();
                activity.TheActivityName = getControlText("txtTheActivityName");

                activity.DestinationString = getDestinationString();
                activity.DestinationValue = getControlText("txtDestinationValue");
                try
                {
                    activity.ValueType = getControlText("radioValueType");
                }
                catch { }

                return activity;
            }
            catch
            {
                return null;
            }
        }

        public override void LoadActivitySettings(Activity activity)
        {
            UpdateAttributeActivity activity2 =
                activity as UpdateAttributeActivity;
            if (activity2 != null)
            {
                setControlText("txtTheActivityName", activity2.TheActivityName);

                setDestinationString(activity2.DestinationString);
                setControlText("txtDestinationValue", activity2.DestinationValue);
                setControlText("radioValueType", activity2.ValueType);
            }
        }

        public override ActivitySettingsPartData PersistSettings()
        {
            ActivitySettingsPartData data = new ActivitySettingsPartData();
            // Take care of the visibility first.
            data["NotesVisible"] = getControlVisible("panelNotes");
            data["ValueTypeVisible"] = getControlVisible("rowValueType");

            data["TheActivityName"] = getControlText("txtTheActivityName");

            data["DestinationString"] = getDestinationString();
            data["DestinationValue"] = getControlText("txtDestinationValue");
            try
            {
                data["ValueType"] = getControlText("radioValueType");
            }
            catch { }
            return data;
        }

        public override void RestoreSettings(ActivitySettingsPartData data)
        {
            if (data != null)
            {
                // Take care of the visibility first.
                setControlVisible("panelNotes", (bool)data["NotesVisible"]);
                setControlVisible("rowValueType", (bool)data["ValueTypeVisible"]);

                setControlText("txtTheActivityName", "" + data["TheActivityName"]);

                setDestinationString("" + data["DestinationString"]);
                setControlText("txtDestinationValue", "" + data["DestinationValue"]);
                setControlText("radioValueType", "" + data["ValueType"]);
            }
        }

        public override void SwitchMode(ActivitySettingsPartMode mode)
        {
            bool readOnly = mode != ActivitySettingsPartMode.Edit;
            setControlReadOnly("txtTheActivityName", readOnly);

            setControlReadOnly("ddlDestinationString", readOnly);
            setControlReadOnly("txtDestinationString", readOnly);
            setControlReadOnly("txtDestinationValue", readOnly);
            setControlReadOnly("radioValueType", readOnly);
        }

        public override string Title
        {
            get
            {
                string[] tokens = this.GetType().ToString().Split('.');
                return tokens[tokens.Length - 1].Replace("SettingsPart", "") + ": " +
                    getControlText("txtTheActivityName");
            }
        }

        public override bool ValidateInputs()
        {
            bool success = true;

            string destination = getControlText("txtDestinationString");
            string value = getControlText("txtDestinationValue");

            string destinationErrorSymbols = "";
            string valueErrorSymbols = "";
            string errorMessages = "";
            bool requiresInputMsgShown = false;

            if (destination.Equals(""))
            {
                destinationErrorSymbols += "*";
                if (!requiresInputMsgShown)
                {
                    errorMessages += "* <Em>Requires input</Em><br />";
                    requiresInputMsgShown = true;
                }
                success = false;
            }

            setControlText("validatorDestinationString", destinationErrorSymbols);
            setControlText("validatorDestinationValue", valueErrorSymbols);
            setControlText("validatorMessages", errorMessages);

            return success;
        }

        #endregion

        #region Private methods

        private void InitializeControls()
        {
            string description;

            mainTable.Width = Unit.Percentage(100.0);
            this.Controls.Add(mainTable);

            //+++ Main Row
            TableRow mainRow = addRowTo(mainTable);
            TableCell mainCell = addCellTo(mainRow);

            Table topTable = new Table();
            topTable.Width = Unit.Percentage(100.0);
            topTable.BorderWidth = 0;
            topTable.CellPadding = 2;
            mainCell.Controls.Add(topTable);

            //--- Table Row
            topTable.Rows.Add(getRow("Activity Name", "",
                "txtTheActivityName", 256, false, "", null));

            //--- Table Row
            topTable.Rows.Add(getSectionLine());
            topTable.Rows.Add(getDestinationRow());

            //--- Table Row
            TableRow valueTypeSectionLine = getSectionLine();
            valueTypeSectionLine.ID = "rowValueTypeSectionLine";
            valueTypeSectionLine.Visible = false;
            topTable.Rows.Add(valueTypeSectionLine);
            description =
@"
Attributes may be arbitrarily stored to WorkflowData and Request objects. Thus, you must define the value type.
";
            List<string> typeLabels = new List<string>
            {
                "String",
                "DateTime",
                "Boolean",
                "Reference",
                "Integer"
            };
            TableRow valueTypeRow = getRow("Value Type", description, typeLabels,
                "radioValueType", 0);
            valueTypeRow.ID = "rowValueType";
            valueTypeRow.Visible = false;
            valueTypeRow.Visible = false;
            topTable.Rows.Add(valueTypeRow);

            //--- Table Row
            topTable.Rows.Add(getSectionLine());
            description =
@"
Supported formats:
<ul>
<li>Any string literal</li>
<li>XPath filter: (case sensitive)<br />
[//Requestor/Manager/ObjectID]<br />
[//Target/FirstName] [//Target/LastName]</li>
<li>Dates in the current culture format:<br />
12/31/1999 (for U.S. English)</li>
<li>Simple date math: (integers represent days)<br />
[//Target/CreatedTime] + 365</li>
</ul>
";
            topTable.Rows.Add(getRow("Destination Value", description,
                "txtDestinationValue", int.MaxValue, true, "", "validatorDestinationValue"));

            topTable.Rows.Add(getSectionLine());

            Label validatorMessages = new Label();
            validatorMessages.CssClass = base.ErrorMessageCssClass;
            validatorMessages.ID = "validatorMessages";
            mainCell.Controls.Add(validatorMessages);
        }

        private TableRow getSectionLine()
        {
            TableRow tempRow = new TableRow();
            TableCell tempCell = new TableCell();
            tempRow.Cells.Add(tempCell);
            tempCell.Attributes.Add("class", "ms-sectionline");
            tempCell.Attributes.Add("height", "1");
            tempCell.Attributes.Add("colspan", "2");
            return tempRow;
        }

        private TableRow addRowTo(Table table)
        {
            TableRow tempRow = new TableRow();
            table.Rows.Add(tempRow);
            return tempRow;
        }

        private TableCell addCellTo(TableRow row)
        {
            TableCell tempCell = new TableCell();
            row.Cells.Add(tempCell);
            return tempCell;
        }

        /// <summary>
        /// Table row for text box input.
        /// </summary>
        private TableRow getRow(String labelText, string description,
            String controlID, int maxLength, Boolean multiLine, string DefaultValue,
            string validatorId)
        {
            TableRow row = new TableRow();
            row.Attributes.Add("rowType", "attributeInfo");
            TableCell labelCell = new TableCell();
            labelCell.VerticalAlign = VerticalAlign.Top;
            TableCell controlCell = new TableCell();
            //controlCell.VerticalAlign = VerticalAlign.Top;

            // Add the label
            Label olabel = new Label();
            olabel.Text = labelText;
            olabel.CssClass = base.LabelCssClass;
            labelCell.Controls.Add(olabel);

            // Validator characters
            Label validatorLabel = new Label();
            validatorLabel.CssClass = base.ErrorMessageCssClass;
            validatorLabel.ID = validatorId;
            labelCell.Controls.Add(validatorLabel);

            // Description
            Panel descriptionPanel = new Panel();
            Label descriptionLabel = new Label();
            descriptionLabel.Text = description;
            descriptionPanel.CssClass = base.DescriptionCssClass;
            descriptionPanel.Controls.Add(descriptionLabel);
            labelCell.Controls.Add(descriptionPanel);

            // Text box
            TextBox oText = new TextBox();
            oText.ID = controlID;
            oText.CssClass = base.TextBoxCssClass;
            oText.Text = DefaultValue;
            oText.MaxLength = maxLength;
            if (multiLine)
            {
                oText.TextMode = TextBoxMode.MultiLine;
                oText.CssClass = "uocTextBox";
                oText.Rows = 10;
                oText.Columns = 60;
            }
            controlCell.Controls.Add(oText);
            row.Cells.Add(labelCell);
            row.Cells.Add(controlCell);
            return row;
        }

        /// <summary>
        /// Table row for radio button inputs.
        /// </summary>
        private TableRow getRow(String labelText, string description,
            List<string> buttonLabels, string buttonListID, int defaultIndex)
        {
            TableRow row = new TableRow();
            row.Attributes.Add("rowType", "attributeInfo");
            TableCell labelCell = new TableCell();
            labelCell.VerticalAlign = VerticalAlign.Top;
            TableCell controlCell = new TableCell();
            //controlCell.VerticalAlign = VerticalAlign.Top;

            // Add the label
            Label olabel = new Label();
            olabel.Text = labelText;
            olabel.CssClass = base.LabelCssClass;
            labelCell.Controls.Add(olabel);

            // Description
            Panel descriptionPanel = new Panel();
            Label descriptionLabel = new Label();
            descriptionLabel.Text = description;
            descriptionPanel.CssClass = base.DescriptionCssClass;
            descriptionPanel.Controls.Add(descriptionLabel);
            labelCell.Controls.Add(descriptionPanel);

            // Radio buttons
            RadioButtonList buttons = new RadioButtonList();
            buttons.ID = buttonListID;
            buttons.CssClass = base.ButtonCssClass;
            for (int i = 0; i < buttonLabels.Count; i++)
            {
                buttons.Items.Add(buttonLabels[i]);
                if (i == defaultIndex)
                {
                    buttons.Items[i].Selected = true;
                }
            }
            controlCell.Controls.Add(buttons);

            row.Cells.Add(labelCell);
            row.Cells.Add(controlCell);
            return row;
        }

        private TableRow getDestinationRow()
        {
            String labelText = "Destination Attribute";
            string description;
            String controlID = "txtDestinationString";
            int maxLength = 256;
            Boolean multiLine = false;
            string DefaultValue = "";
            string validatorId = "validatorDestinationString";

            description =
@"
Examples:
<ul>
<li>[//Target/DisplayName]</li>
<li>[//Requestor/Manager]</li>
</ul>
";

            TableRow row = new TableRow();
            row.Attributes.Add("rowType", "attributeInfo");
            TableCell labelCell = new TableCell();
            labelCell.VerticalAlign = VerticalAlign.Top;
            TableCell controlCell = new TableCell();
            //controlCell.VerticalAlign = VerticalAlign.Top;

            // Add the label
            Label olabel = new Label();
            olabel.Text = labelText;
            olabel.CssClass = base.LabelCssClass;
            labelCell.Controls.Add(olabel);

            // Validator characters
            Label validatorLabel = new Label();
            validatorLabel.CssClass = base.ErrorMessageCssClass;
            validatorLabel.ID = validatorId;
            labelCell.Controls.Add(validatorLabel);

            // Description
            Panel descriptionPanel = new Panel();
            Label descriptionLabel = new Label();
            descriptionLabel.Text = description;
            descriptionPanel.CssClass = base.DescriptionCssClass;
            descriptionPanel.Controls.Add(descriptionLabel);
            labelCell.Controls.Add(descriptionPanel);

            // List box
            DropDownList dropDownList = new DropDownList();
            ListItem[] listItems = new ListItem[]
            {
                new ListItem("Target"),
                new ListItem("Requestor"),
                new ListItem("WorkflowData"),
                new ListItem("Request")
            };
            dropDownList.Items.AddRange(listItems);
            dropDownList.SelectedIndexChanged += new EventHandler(dropDownList_SelectedIndexChanged);
            dropDownList.AutoPostBack = true;
            dropDownList.ID = "ddlDestinationString";
            dropDownList.Style.Add("vertical-align", "middle");

            // Text box
            Panel inputPanel = new Panel();
            inputPanel.CssClass = "ms-siteaction ms-vb-tall";
            Label prefixLabel = new Label();
            prefixLabel.Text = "[//";
            prefixLabel.ID = controlID + "Prefix";
            Label midLabel = new Label();
            midLabel.Text = "/";
            midLabel.ID = controlID + "Middle";
            Label suffixLabel = new Label();
            suffixLabel.Text = "]";
            suffixLabel.ID = controlID + "Suffix";
            TextBox oText = new TextBox();
            oText.ID = controlID;
            oText.Style.Add("vertical-align", "middle");
            oText.CssClass = "uocTextBox";
            oText.Text = DefaultValue;
            oText.MaxLength = maxLength;
            oText.Rows = 10;
            if (multiLine)
            {
                oText.TextMode = TextBoxMode.MultiLine;
                oText.CssClass = "uocTextBox";
                oText.Rows = 10;
                oText.Columns = 60;
            }
            inputPanel.Controls.Add(prefixLabel);
            inputPanel.Controls.Add(dropDownList);
            inputPanel.Controls.Add(midLabel);
            inputPanel.Controls.Add(oText);
            inputPanel.Controls.Add(suffixLabel);

            controlCell.Controls.Add(inputPanel);

            row.Cells.Add(labelCell);
            row.Cells.Add(controlCell);
            return row;
        }

        private void setControlReadOnly(string controlID, Boolean readOnly)
        {
            Control target = this.FindControl(controlID);
            try
            {
                if (target.GetType() == typeof(TextBox))
                {
                    TextBox oText = (TextBox)target;
                    if (oText != null)
                    {
                        oText.ReadOnly = readOnly;
                    }
                    return;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(RadioButtonList))
                {
                    RadioButtonList buttons = (RadioButtonList)target;
                    if (buttons != null)
                    {
                        buttons.Enabled = !readOnly;
                    }
                    return;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(DropDownList))
                {
                    DropDownList dropDownList = (DropDownList)target;
                    if (dropDownList != null)
                    {
                        dropDownList.Enabled = !readOnly;
                    }
                    return;
                }
            }
            catch { }
        }

        private string getControlText(string controlID)
        {
            Control target = this.FindControl(controlID);
            try
            {
                if (target.GetType() == typeof(TextBox))
                {
                    TextBox textBox = (TextBox)target;
                    return textBox.Text;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(Label))
                {
                    Label label = (Label)target;
                    return label.Text;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(DropDownList))
                {
                    DropDownList dropDown = (DropDownList)target;
                    return dropDown.SelectedValue;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(RadioButtonList))
                {
                    RadioButtonList buttons = (RadioButtonList)target;
                    return buttons.SelectedValue;
                }
            }
            catch { }
            return "[Control '" + controlID + "' not found]";
        }

        private void setControlText(string controlID, string value)
        {
            Control target = this.FindControl(controlID);
            try
            {
                if (target.GetType() == typeof(TextBox))
                {
                    TextBox textBox = (TextBox)target;
                    textBox.Text = value;
                    return;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(Label))
                {
                    Label label = (Label)target;
                    label.Text = value;
                    return;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(DropDownList))
                {
                    DropDownList dropDown = (DropDownList)target;
                    dropDown.SelectedValue = value;
                    return;
                }
            }
            catch { }
            try
            {
                if (target.GetType() == typeof(RadioButtonList))
                {
                    RadioButtonList buttons = (RadioButtonList)target;
                    buttons.SelectedValue = value;
                    return;
                }
            }
            catch { }
        }

        private int getControlIndex(string controlID)
        {
            Control target = this.FindControl(controlID);
            try
            {
                if (target.GetType() == typeof(RadioButtonList))
                {
                    RadioButtonList buttons = (RadioButtonList)target;
                    return buttons.SelectedIndex;
                }
            }
            catch { }
            throw new ArgumentOutOfRangeException("Could not get control index of " + controlID);
        }

        private void setControlIndex(string controlID, int value)
        {
            Control target = this.FindControl(controlID);
            try
            {
                if (target.GetType() == typeof(RadioButtonList))
                {
                    RadioButtonList buttons = (RadioButtonList)target;
                    buttons.SelectedIndex = value;
                    return;
                }
            }
            catch { }
        }

        private bool getControlVisible(string controlID)
        {
            bool visible = true;
            Control target = this.FindControl(controlID);
            if (target != null)
            {
                visible = target.Visible;
            }
            return visible;
        }

        private void setControlVisible(string controlID, Boolean visible)
        {
            Control target = this.FindControl(controlID);
            if (target != null)
            {
                target.Visible = visible;
            }
        }

        private void dropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                DropDownList source = (DropDownList)sender;
                bool showValueType = false;
                switch (source.SelectedValue)
                {
                    case "Request":
                    case "WorkflowData":
                        showValueType = true;
                        break;
                    case "Target":
                    case "Requestor":
                    default:
                        showValueType = false;
                        break;
                }
                setControlVisible("rowValueTypeSectionLine", showValueType);
                setControlVisible("rowValueType", showValueType);
            }
            catch { }
        }

        private string getDestinationString()
        {
            string result = "[//" +
                getControlText("ddlDestinationString") +
                "/" +
                getControlText("txtDestinationString") +
                "]";
            return result;
        }

        private void setDestinationString(string input)
        {
            string destinationString = null;

            if (input.IndexOf("//Requestor/") >= 0)
            {
                destinationString = "Requestor";
            }
            else if (input.IndexOf("//Request/") >= 0)
            {
                destinationString = "Request";
            }
            else if (input.IndexOf("//Target/") >= 0)
            {
                destinationString = "Target";
            }
            else if (input.IndexOf("//WorkflowData/") >= 0)
            {
                destinationString = "WorkflowData";
            }
            else { }

            if (destinationString != null)
            {
                setControlText("ddlDestinationString", destinationString);
                // Call the event handler manually.
                Control dropDown = FindControl("ddlDestinationString");
                dropDownList_SelectedIndexChanged(dropDown, new EventArgs());

                char[] delimiters = { '/' };
                string[] destinationTokens = input
                    .Replace('[', delimiters[0]).Replace(']', delimiters[0])
                    .Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
                if (destinationTokens != null && destinationTokens.Length > 1)
                {
                    setControlText("txtDestinationString", destinationTokens[1]);
                }
            }
        }

        #endregion

    }
}
